using System;
using System.Text;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.Serialization;

using Crainiate.Data.Persistence.Cache;

namespace Crainiate.Data.Persistence
{
    [Serializable]
    public class Column: IColumn, ISerializable
    {
        //Property variables
        private PropertyInfo _propertyInfo;

        //Cosntructors
        public Column(Type type, string name)
        {
            _propertyInfo = type.GetProperty(name);
            if (_propertyInfo == null) throw new PersistenceException("Property " + name + " could not be found for type " + type.FullName);
        }

        public Column(PropertyInfo property)
        {
            if (property == null) throw new ArgumentNullException("The property argument may not be null for a Field constructor.");
            _propertyInfo = property;
        }

        protected Column(SerializationInfo info, StreamingContext context)
        {
            Type type = Component.ResolveType(info.GetString("Type"));
            if (type == null) throw new PersistenceException("Type could not be resolved for " + info.GetString("Type"));

            _propertyInfo = type.GetProperty(info.GetString("Name"));
        }

        //Properties
        public PropertyInfo PropertyInfo
        {
            get
            {
                return _propertyInfo;
            }
        }

        //Methods
        public override int GetHashCode()
        {
            PropertyInfo prop = PropertyInfo;
            
            if (typeof(IView).IsAssignableFrom(prop.ReflectedType))
            {
                ReflectionCacheItem cache = Component.Instance.ReflectionCache.Lookup(prop.ReflectedType);
                prop = cache.GetOriginalProperty(prop);
            }
            
            return prop.ToString().GetHashCode();
        }

        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Type", _propertyInfo.ReflectedType.FullName);
            info.AddValue("Name", _propertyInfo.Name);
        }

    }
}
